<?php
/**
 * 文件名：mysql.db.php
 * 版本号：1.0
 * 最后修改时间：2011年5月3日 14
 * 作者：狐狸<foxis@qq.com>
 * 功能描述：MYSQL处理,连接MYSQL,取得,修改,添加,删除数据
 */
if(!defined('IN_JISHIGOU'))
{
    exit('invalid request');
}
require_once ROOT_PATH.'/include/memcache/memcacheDB.php';
require_once ROOT_PATH.'/include/db/changesql.db.php';
class MySqlHandler extends DatabaseHandler
{
    var $TableName;     var $FieldList;

    var $Charset='gbk';


    function MySqlHandler($server_host, $server_port = '3306')
    {
        $this->DatabaseHandler($server_host, $server_port);
    }

    function DoConnect($username, $password, $database, $persist = true,$setkey=1)
    {
        $host = $this->ServerHost . ':' . $this->ServerPort;

        if($persist)
        {
            @$db=mysql_pconnect($host, $username, $password,true);
        }
        else
        {
            @$db=mysql_connect($host, $username, $password,true);
        }
        $db==false?exit(mysql_errno().":".mysql_error()):$this->setConnectionId($db);

        if($this->GetVersion() > '4.1')
        {
            if($this->Charset)
            {
                @mysql_query("SET character_set_connection={$this->Charset},
                character_set_results={$this->Charset},
                character_set_client=binary",$db);
            }

            if($this->GetVersion() > '5.0.1')mysql_query("SET sql_mode=''",$db);
        }

        if(false == mysql_select_db($database, $this->GetConnectionId()))
        {
            $this->setConnectionId(0);
        }
    }

    function Charset($charset)
    {
        $this->Charset = ((false!==strpos($charset,'-')) ? str_replace("-", "", strtolower($charset)) : $charset);
    }

	function QueryCache($sql,$cache){
		return $this->Query($sql,"");
	}


    function Query($sql,$type='')
    {
        $changesql_db= new changesql_db($this,$sql);
        $sql = $changesql_db->sql;
        
		if(DatabaseHandler::$noCache)
			$memcacheDB = new nocacheDB($sql);
		else
			$memcacheDB = new memcacheDB($sql);
        $memch_r=$memcacheDB->getvalue();
        if(!empty($memch_r)){
            return new MySqlIterator("memcache",$memcacheDB);
        }

        $func=$type==='UNBUFFERED'?'mysql_unbuffered_query':'mysql_query';
        $result = $func($sql, $this->GetConnectionId());
        if($result==false)
        {
            if(in_array($this->GetLastErrorNo(), array(2006, 2013)) && substr($type, 0, 5) != 'RETRY') {
                $this->CloseConnection();

                include ROOT_PATH . 'setting/settings.php';
                $this->MySqlHandler($config['db_host'],$config['db_port']);
                $this->Charset($config['charset']);
                $this->DoConnect($config['db_user'],$config['db_pass'],$config['db_name'],$config['db_persist'],0);

                $result = $this->Query($sql, 'RETRY'.$type);
            } elseif (in_array($this->GetLastErrorNo(), array(1040)) && substr($type,0,4) != "WAIT" && substr($type,0,5) < "WAIT3") {
                usleep(100000 * max(1,min(6,2 * ((int) substr($type,4,1) + 1))));

                $result = $this->Query($sql, 'WAIT'.++$WAITTIMES.$type);
            } elseif ($type != 'SKIP_ERROR' && 'SILENT' != $type && substr($type, 5) != 'SKIP_ERROR') {
                die($this->GetLastError($sql, $file, $line));
            } else {
                return false;
            }
        }

        return new MySqlIterator($result,$memcacheDB);
    }
    function fetch_first($sql)
    {
        return $this->FetchFirst($sql);
    }
    function FetchFirst($sql)
    {
        $result = array();

        $query = $this->Query($sql);

        if($query)
        {
            $result = $query->GetRow();
        }

        return $result;
    }
    function ResultFirst($sql)
    {
        $result = '';

        $query = $this->Query($sql);

        if($query)
        {
            $result = $query->result(0);
        }

        return $result;
    }

    function SetTable($tableName,$skip_error=false)
    {
        $this->TableName = $tableName;
        if(isset($this->Table[$tableName]))
        {
            $this->FieldList = $this->Table[$tableName];
        }
        else
        {
            if (($fieldList=cache("table/{$tableName}",-1))===false)
            {
                $sql = "SHOW \n\tCOLUMNS \nFROM \n\t`{$this->TableName}`";
                $query = $this->Query($sql,$skip_error?"SKIP_ERROR":"");
                if($query==false)return false;
                $fieldList = array();
                while($row = $query->GetRow())
                {
                    if($row['Extra'] === "auto_increment")
                    {
                        $fieldList[$row['Key']] = $row['Field'];
                    }
                    else
                    {
                        $fieldList[] = $row['Field'];
                    }
                }
                cache($fieldList);
            }
            $this->FieldList = $fieldList;
            $this->Table[$tableName] = $fieldList;
        }
        Return $this->FieldList;
    }
    function Select($id = '', $condition = NULL, $fields = "*")
    {
        if($condition === NULL)
        {
            if($ids = $this->BuildIn($id))
            {
                $where = "\r\nWHERE \n\t" . $ids;
            }
            else
            {
                Return false;
            }
        }
        else
        {
            if(trim($condition) != "")
            {
                $where = "\r\nWHERE \n\t" . $condition;
            }
        }

        $fieldNames = "\n\t*";
        $field_num=0;
        if($fields != "*")
        {
            $fieldNames = "\n\t".$this->FieldList['PRI'];
            if(is_string($fields) != false)
            {
                $field_list = explode(',', $fields);
            }elseif(is_array($fields) != false)
            {
                $field_list = array_filter($fields, 'strlen');
            }
            $valid_field_list=array();
            foreach($field_list as $key => $field)
            {
                if(in_array($field, $this->FieldList))
                {
                    $fieldNames .= ",\n\t`" . $field . '`';
                    $valid_field_list[]=$field;
                }
            }
            $field_num=count($valid_field_list);
            $fieldNames = ($field_num>=1)?ltrim($fieldNames, ",\n\t"):"\n\t*";
        }

        $sql = "SELECT {$fieldNames} \nFROM \n\t`{$this->TableName}` {$where}";

        $query = $this->query($sql);
        $data_list = array();
        if($field_num==1)$field_name=implode('',$valid_field_list);
        if($query->GetNumRows() > 1)
        {
            while($row = $query->GetRow())
            {
                $data_list[$row[$this->FieldList['PRI']]] =($field_num==1)?$row[$field_name]:$row;
            }
        }
        else
        {
            $row = $query->GetRow();
            $data_list =($field_num==1)?$row[$field_name]:$row;
        }
        Return $data_list;
    }
    function Replace($dataList)
    {
        if($dataList == "")Return false;
        foreach($this->FieldList as $key => $field)
        {
            if(isset($dataList[$field]))
            {
                $fieldNames .= ",\n\t`" . $field . '`';
                $fieldValues .= ",\n\t\"" . $dataList[$field] . "\"";
            }
        }
        $sql = sprintf("REPLACE INTO \n\t`%s`(%s) \nVALUES(%s)", $this->TableName, ltrim($fieldNames, ','), ltrim($fieldValues, ','));
        $this->query($sql);

        return $this->Insert_ID();
    }
    function Insert($dataList,$continue_primary_key=true)
    {
        if(($sql=$this->BuildInsert($this->TableName,$dataList,$continue_primary_key,true))=="")return false;
        $this->query($sql);
        return $this->Insert_ID();
    }
    function Update($dataList, $condition = NULL)
    {
        if(($sql=$this->BuildUpdate($this->TableName,$dataList,$condition,true))=="")return false;
        if ($this->query($sql))
        {
            return $this->AffectedRows();
        }
        else
        {
            return false;
        }
    }
    function Delete($id = "", $condition = NULL)
    {
        if($condition === NULL)
        {
            if($ids = $this->BuildIn($id))
            {
                $where = "WHERE " . $ids;
            }
            else
            {
                Return false;
            }
        }
        else
        {
            if(trim($condition) != "")
            {
                $where = "\r\nWHERE \n\t" . $condition;
            }
        }

        $sql = "DELETE FROM `{$this->TableName}` {$where}";
        if ($this->query($sql))
        {
            return $this->AffectedRows();
        }
        else
        {
            return false;
        }
    }

    function BuildField($mixed)
    {
        if($mixed==false or trim($mixed)=="*")Return "*";
        $type=gettype($mixed);
        if($type=="string" or $type=="integer" or $type=="double")
        {
            $mixed=trim($mixed,',');
            $mixed=strpos($mixed,',')!==false?"'".str_replace(',',"`,`",$mixed)."'":"`$mixed`";
        }
        elseif($type=="array")
        {
            $mixed="`".implode("`,`",$mixed)."`";
        }
        Return $mixed;
    }

    function BuildInsert($tableName,$dataList,$continue_primary_key=true,$filterValid=false)
    {
        if(is_array($dataList) == false)Return '';
        if($filterValid===true)
        {
            $this->SetTable($tableName);
            foreach($this->FieldList as $key => $field)
            {
                if(strcmp($key, "PRI") === 0 and $continue_primary_key===true)
                {
                    continue;
                }
                if(isset($dataList[$field]))
                {
                    $fieldNames .= ",\n\t`" . $field . '`';
                    $fieldValues .= ",\n\t\"" . $dataList[$field] . "\"";
                }
            }
            if ($fieldNames=='' or $fieldValues=='')return '';
        }
        else
        {
            foreach($dataList as $field=>$value)
            {
                $fieldNames .= ",\n\t`" . $field . '`';
                $fieldValues .= ",\n\t\"" .$value. "\"";
            }
            $this->TableName=$tableName;
        }
        $sql = sprintf("INSERT INTO \n\t`%s`(%s) \nVALUES(%s)", $tableName, ltrim($fieldNames, ','), ltrim($fieldValues, ','));
        return $sql;
    }

    function BuildUpdate($tableName,$dataList,$condition=null,$filterValid=false)
    {
        if(is_array($dataList) == false)Return '';
        if($filterValid===true)
        {
            $this->SetTable($tableName);
            foreach($this->FieldList as $key => $field)
            {
                if(isset($dataList[$field]))
                {
                    if($key === "PRI")
                    {
                        if($ids = $this->BuildIn($dataList[$field]))$where = "WHERE \n\t" . $ids;
                    }
                    else
                    {
                        $value=$dataList[$field];
                        $fieldUpdate .=strpos($value, 'eval:') === 0?"\n\t`{$field}`=".substr($value, 5).",":"\n\t`{$field}`='{$value}',";
                    }
                }
            }
        }
        else
        {
            $this->TableName=$tableName;
            foreach ($dataList as $field=>$value)
            {
                $fieldUpdate .= strpos($value, 'eval:') === 0?"\n\t`{$field}`=".substr($value, 5).",":"\n\t`{$field}`='{$value}',";
            }
        }
        if($fieldUpdate == '')Return '';
        if($condition !== NULL)
        {
            $where = (trim($condition) != "")?"WHERE \n\t" . $condition:"";
        }
        elseif($filterValid==true)
        {
            if($dataList[$this->FieldList['PRI']] == "")Return '';
        }
        $sql = sprintf("UPDATE \n\t`%s` \t\nSET %s \n%s", $this->TableName, rtrim($fieldUpdate, ','), $where);
        return $sql;
    }
    function BuildIn($mixed,$name=null)
    {
        if($name === NULL)$name = $this->FieldList['PRI'];
        $type=gettype($mixed);
        if($type=="string" or $type=="integer" or $type=="double")
        {
            $mixed=trim($mixed,',');
            $mixed=strpos($mixed,',')!==false
            ?"'".str_replace(',',"','",$mixed)."'"
            :"'$mixed'";
        }
        elseif($type=="array")
        {
            $mixed=!empty($mixed)?"'".implode("','",array_unique($mixed))."'":'null';
        }

        Return $name!=null?"$name IN ($mixed)":$mixed;
    }


    function GetVersion()
    {
        return mysql_get_server_info($this->GetConnectionId());
    }


    function GetLastError($sql, $file, $line)
    {
        $error = mysql_error($this->GetConnectionId());

        return $error . $sql;
    }
    function GetLastErrorString()
    {
        return mysql_error($this->GetConnectionId());
    }
    function GetLastErrorNo()
    {
        return mysql_errno($this->GetConnectionId());
    }


    function Insert_ID()
    {
        return mysql_insert_id($this->GetConnectionId());
    }

    function LastInsertId()
    {
        $this->Insert_ID();
    }


    function AffectedRows()
    {
        Return mysql_affected_rows($this->GetConnectionId());
    }


    function CloseConnection()
    {
        return mysql_close($this->GetConnectionId());
    }
}



class MySqlIterator
{

    var $_resource_id;


    var $_current_row;


    var $_total_rows;
    var $memcacheDB ;
    var $M_cache ;

    function MySqlIterator($resource_id,$memcacheDB)
    {
        $this->_resource_id = $resource_id;
        $this->_total_rows = 0;
        $this->_current_row = 0;
        $this->memcacheDB=$memcacheDB;
    }


    function GetNumRows()
    {
        $result = $this->memcacheDB->getresult();
        if(!empty($result)){
            $this->_total_rows = sizeof($result);
            return $this->_total_rows;
        }
        $this->_total_rows = mysql_num_rows($this->GetResourceId());
        return $this->_total_rows;
    }

    function GetNumFields()
    {
        return mysql_num_fields($this->GetResourceId());
    }


    function GetResourceId()
    {
        return $this->_resource_id;
    }


    function GetCurrentRow()
    {
        return $this->_current_row;
    }


    function isSuccess()
    {
        return $this->GetResourceId() ? true : false;
    }


    function _freeResult()
    {
        mysql_free_result($this->GetResourceId());

        return;
    }


    function GetRow($result_type = 'assoc')
    {
        $this->_current_row++;
        $result = $this->memcacheDB->getresult();
            
        if(!empty($result)){
            return $result[$this->_current_row-1];
        }
        if(empty($this->M_cache)){
            while ($row = $this->GetRowS($result_type)){
                $this->M_cache[] = $row;
            }
        }
        $this->memcacheDB->setvalue($this->M_cache);
        if(empty($this->M_cache[$this->_current_row-1])){
            return false;
        }
        return $this->M_cache[$this->_current_row-1];
    }
    
    function GetRowS($result_type = 'assoc'){
        switch($result_type)
        {
            case 'row':
                return mysql_fetch_row($this->GetResourceId());
                break;
            case 'assoc':
                return mysql_fetch_assoc($this->GetResourceId());
                break;
            case 'both':
                return mysql_fetch_array($this->GetResourceId());
                break;
            case 'object':
                return mysql_fetch_object($this->GetResourceId());
                break;
        }
    }



    function result($row)
    {
        return @mysql_result($this->GetResourceId(),$row);
    }


    function GetAll($result_type = 'assoc')
    {
        $list = array();
        while($row = $this->GetRow($result_type))
        {
            $list[] = $row;
        }
        Return $list;
    }
}

?>